package com.qilin.hscs.hm.mqtt.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.qilin.hscs.hm.convert.BaseConvert;
import com.qilin.hscs.hm.convert.DTO2DOConvert;
import com.qilin.hscs.hm.dao.GatewayRepository;
import com.qilin.hscs.hm.dto.*;
import com.qilin.hscs.hm.dao.DeviceRepository;
import com.qilin.hscs.hm.dao.DeviceTypeRepository;
import com.qilin.hscs.hm.dao.RoomRepository;
import com.qilin.hscs.hm.enums.DeviceClusterEnum;
import com.qilin.hscs.hm.mqtt.service.DeviceService;
import com.qilin.hscs.hm.pojo.DeviceType;
import com.qilin.hscs.hm.util.MqttResultUtil;
import com.qilin.hscs.hm.mqtt.service.common.ServiceCommon;
import com.qilin.hscs.hm.pojo.Device;
import com.qilin.hscs.hm.pojo.Room;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author 胡晓军
 * @date 2018/3/23
 * 处理device业务逻辑的类，它仅与逻辑处理中心进行双向交互
 */
@Service("device")
@Transactional
public class DeviceServiceImpl extends ServiceCommon implements DeviceService {

    private JSONObject msgObj=null;

    private JSONObject dataObj=null;

    private static final String deviceName = "设备";

    //未分配房间的id  默认未1
    private static final int defaultRoomId=1;

    private static final Logger logger= LogManager.getLogger(DeviceServiceImpl.class.getName());

    @Autowired
    private DeviceRepository repository;

    @Autowired
    private DeviceTypeRepository deviceTypeRepository;

    @Autowired
    private GatewayRepository gatewayRepository;

    @Autowired
    private RoomRepository roomRepository;




    @Override
    public void addDevice() {
        logger.info("添加设备");
        DeviceDto deviceDto=readDataTODeviceDto();
        List<Device> devices = DTO2DOConvert.deviceDto2DeviceList(deviceDto);
        Room room = roomRepository.findOne(defaultRoomId);
        for (Device device : devices) {
            Device byIeeeAndEp = repository.findByIeeeAndEp(device.getIeee(), device.getEp());
            if (byIeeeAndEp==null) {
                DeviceType type = deviceTypeRepository.findByEpt(device.getEpt());
                device.setName(type.getName() + device.getEp());
                device.setIcon(type.getIcon());
                device.setRoomId(defaultRoomId);
                Device re = repository.save(device);
            }else {
                logger.info("设备已经添加，请勿重复添加");
            }
        }
        Map<String, Object> data = new HashMap<>(5);
        data.put("room", room);
        data.put("eps", deviceDto.getEps());
        data.put("ieee", deviceDto.getIeee());
        data.put("uid", deviceDto.getUid());      //todo 也可以封装成一个vo来返还数据
        msg = MqttResultUtil.getResult(5003,0,data);
    }

    @Override
    public void alterDevice() {
        logger.info("修改设备");
        SingleBaseDeviceEPDto baseDeviceEPDto = readDataToSingleBaseDeviceDto();
        String ieee = StringUtils.join(baseDeviceEPDto.getIeee(), ",");
        Device deviceEp = repository.findByIeeeAndEp(ieee, baseDeviceEPDto.getEp());
        BeanUtils.copyProperties(baseDeviceEPDto,deviceEp);
        Device re=repository.save(deviceEp);
        msg = MqttResultUtil.getResult(5002, 0, re);
    }

    @Override
    public void findTotalDevice() {
        logger.info("找出所有设备");
        List<Device> devices = repository.findAll();
        List<String> floors=roomRepository.findAllFloor();
        List<Room> rooms=roomRepository.findAll();
        List<Map<String, Object>> distinctDevices = repository.findDistinctDevice();
        List<Map<String, Object>> floorsObj = new ArrayList<>();
        for (String floor : floors) {
            List<Map<String,Object>> roomsRe = new ArrayList<>();
            Map<String, Object> floorObj = new HashMap<>();
            for (Room room : rooms) {
                if (room.getFloor().equals(floor)) {
                    Map<String, Object> roomRe = new HashMap<>();
                    roomRe.put("id", room.getId());
                    roomRe.put("name", room.getName());
                    roomRe.put("icon", room.getIcon());
                    List<Map<String, Object>> devicesObj = new ArrayList<>();
                    for (Map<String, Object> distinctDevice : distinctDevices) {
                        if ((Integer)distinctDevice.get("roomId") == room.getId()) {
                            Map<String, Object> deviceObj = new HashMap<>();
                            deviceObj.put("ieee", distinctDevice.get("ieee"));
                            deviceObj.put("uid", distinctDevice.get("uid"));
                            List<DeviceEPDto> eps = new ArrayList<>();
                            for (Device device : devices) {
                                if (device.getIeee().equals(String.valueOf(distinctDevice.get("ieee")))) {
                                    DeviceEPDto dto = new DeviceEPDto();
                                    BeanUtils.copyProperties(device, dto);
                                    eps.add(dto);
                                }
                            }
                            deviceObj.put("eps", eps);
                            devicesObj.add(deviceObj);
                        }
                    }
                    roomRe.put("devices", devicesObj);
                    roomsRe.add(roomRe);
                }
            }
            floorObj.put("floor", floor);
            floorObj.put("rooms", roomsRe);
            floorsObj.add(floorObj);
        }
        Map<String, Object> data = new HashMap<>();
        data.put("phone", phone);
        data.put("floors",floorsObj);
        msg = MqttResultUtil.getResult(5001, 0, data);
    }

    @Override
    public void delDevice() {
        DeviceDto deviceDto = readDataTODeviceDto();
        String ieee = StringUtils.join(deviceDto.getIeee(), ",");
        int re=repository.deleteByIeee(ieee);
        System.out.println(re);
        if (re>0) {
            Map<String, Object> data = new HashMap<>();    //todo  删除和设备相关的绑定信息
            data.put("phone", phone);
            data.put("IEEE", deviceDto.getIeee());
            data.put("UID", deviceDto.getUid());
            msg = MqttResultUtil.getResult(5005, 0, data);
        }
    }
    @Override
    public void findControllerDevice() {
        List<Device> devices = findByType(DeviceClusterEnum.SWITCH.getClu());
        Map<String, Object> data = new HashMap<>();
        data.put("phone", phone);
        data.put("devices", devices);
        msg = MqttResultUtil.getResult(5011, 0, data);
    }

    @Override
    public void  uploadControllerState() {
        logger.info("控制类状态上传");
        DeviceEPStateDto deviceEPStateDto = readDataToDeviceEPStateDto();
        String ieee = StringUtils.join(deviceEPStateDto.getIeee(), ",");
        Device byIeeeAndEp = repository.findByIeeeAndEp(ieee, deviceEPStateDto.getEp());
        byIeeeAndEp.setSts(deviceEPStateDto.getSts());
        Device re = repository.save(byIeeeAndEp);
        Map<String, Object> data = new HashMap<>();
        data.put("ieee", re.getIeee());
        data.put("uid", re.getUid());
        data.put("sts", re.getSts());
        data.put("ep", re.getEp());
        msg = MqttResultUtil.getResult(5006, 0, data);
    }

    @Override
    public void  uploadSensorState() {
        logger.info("传感器类状态上传");
        DeviceEPStateDto deviceEPStateDto = readDataToDeviceEPStateDto();
        String ieee = StringUtils.join(deviceEPStateDto.getIeee(), ",");
        Device byIeeeAndEp = repository.findByIeeeAndEp(ieee, deviceEPStateDto.getEp());
        byIeeeAndEp.setNum(deviceEPStateDto.getNum());
        Device re = repository.save(byIeeeAndEp);
        Map<String, Object> data = new HashMap<>();
        data.put("ieee", re.getIeee());
        data.put("uid", re.getUid());
        data.put("sts", re.getNum());
        data.put("ep", re.getEp());
        msg = MqttResultUtil.getResult(5006, 0, data);
    }

    @Override
    public void findByFloorAndRoom() {
        logger.info("根据楼层和房间号查询设备");
        int rId = dataObj.getIntValue("rId");
        List<Map<String, String>> ieees = repository.findIeeesByRoomId(rId);
        List<Device> devices = repository.findByRoomId(rId);
        List<DeviceDto> deviceDtos = new ArrayList<>();
        for (Map<String,String> ieeeAndUid:ieees) {
            DeviceDto deviceDto=new DeviceDto();
            List<DeviceEPDto> eps = new ArrayList<>();
            for (Device device:devices) {
                if (device.getIeee().equals(ieeeAndUid.get("ieee"))) {
                    DeviceEPDto epDto = new DeviceEPDto();
                    BeanUtils.copyProperties(device, epDto);
                    eps.add(epDto);
                }
            }
            deviceDto.setIeee(BaseConvert.string2IntegerArr(ieeeAndUid.get("ieee")));
            deviceDto.setUid(BaseConvert.string2IntegerArr(ieeeAndUid.get("uid")));
            deviceDto.setEps(eps);
            deviceDtos.add(deviceDto);
        }
        Map<String, Object> data = new HashMap<>();
        data.put("phone", phone);
        data.put("devices", deviceDtos);
        msg = MqttResultUtil.getResult(5008, 0, data);
    }

    @Override
    public void alterRoomInfoOfDevice() {
        String ieee = StringUtils.join(dataObj.getJSONArray("ieee"), ",");
        List<Device> devices = repository.findByIeee(ieee);
        List<Device> devicesRe = new ArrayList<>();
        Integer rId = dataObj.getInteger("rId");
        for (Device device : devices) {
            device.setRoomId(rId);
            Device re = repository.save(device);
            devicesRe.add(re);
        }
        msg = MqttResultUtil.getResult(5009, 0, devicesRe);
    }


    private final DeviceDto readDataTODeviceDto() {
        //JSONObject deviceObj = msgObj.getJSONObject("device");
        DeviceDto deviceDto = dataObj.toJavaObject(DeviceDto.class);
        logger.debug(deviceDto);
        return deviceDto;
    }

    private final SingleBaseDeviceEPDto readDataToSingleBaseDeviceDto() {
        SingleBaseDeviceEPDto baseDeviceEPDto = dataObj.toJavaObject(SingleBaseDeviceEPDto.class);
        logger.debug(baseDeviceEPDto);
        return baseDeviceEPDto;
    }

    private final DeviceEPStateDto readDataToDeviceEPStateDto() {
        DeviceEPStateDto deviceEPStateDto = dataObj.toJavaObject(DeviceEPStateDto.class);
        logger.debug(deviceEPStateDto);
        return deviceEPStateDto;
    }

    private final List<Device> findByType(Integer clu) {
        List<DeviceType> deviceTypes = deviceTypeRepository.findByClu(clu);
        List<Integer> epts = deviceTypes.stream().map(e -> e.getEpt()).collect(Collectors.toList());
        List<Device> devices = repository.findByEptIn(epts);
        return devices;
    }

    @Override
    public void handle() {
        switch (cmd) {
            case 4001:
                findTotalDevice();
                isflushToGateway(false);
                flush();
                break;
            case 4002:
                alterDevice();
                isflushToGateway(false);
                flush();
                break;
            case 4003:
                isflushToGateway(true);
                flush();
                break;
            case 4004:
                findControllerDevice();
                isflushToGateway(false);
                flush();
                break;
            case 4005:
                isflushToGateway(true);
                flush();
                break;
            case 4006:
                isflushToGateway(true);
                flush();
                break;
            case 4007:
                isflushToGateway(true);
                flush();
                break;
            case 4008:
                findByFloorAndRoom();
                isflushToGateway(false);
                flush();
                break;
            case 4009:
                alterRoomInfoOfDevice();
                isflushToGateway(false);
                flush();
                break;
            case 5003:
                addDevice();
                isflushToGateway(false);
                flush();
                break;
            case 5005:
                delDevice();
                isflushToGateway(false);
                flush();
                break;
            case 5006:
                uploadControllerState();
                isflushToGateway(false);
                flush();
                break;
            case 5007:
                uploadSensorState();
                isflushToGateway(false);
                flush();
                break;
            default:
        }
    }

    @Override
    public void initailData() {
        try {
            msgObj = JSON.parseObject(msg);
            dataObj = msgObj.getJSONObject("data");
            if (dataObj!=null) {
                phone = dataObj.getString("phone");
            }
        } catch (JSONException je) {
            logger.warn("传输过来的json字符串有误，主机无法解析 错误详细情况为={}", je.getStackTrace());
        }
        cmd = msgObj.getInteger("cmd");
    }
}
